home *** CD-ROM | disk | FTP | other *** search
/ Nebula 2 / Nebula Two.iso / SourceCode / MiscKit1.7.1 / MiscKit / Source / MiscGISKit / MiscCoordConverter.m < prev    next >
Text File  |  1995-07-20  |  10KB  |  307 lines

  1. /*========================= MiscCoordConverter.m ============================*/
  2. /* MiscCoordConverter is an abstract super class that supports the writing of
  3.    converters between coordinate systems. All values are double precision
  4.    floating point numbers representing locations in a three dimensional
  5.    coordinate system.
  6.  
  7.    DMA Release 0.8, Copyright @1993 by Genesis Project, Ltd. All Rights
  8.    Reserved. For further information on terms and conditions see
  9.         the MiscKit license.
  10.  
  11. HISTORY
  12. 10-Mar-93  Dale Amon at GPL
  13.        Created.
  14. */
  15.  
  16. #import <misckit/miscgiskit.h>
  17.  
  18. @implementation MiscCoordConverter
  19.  
  20. /*===========================================================================*/
  21. /* Internal Class Subcontractor support methods */
  22. /*===========================================================================*/
  23. /* register a converter to the list of conversion subcontractors */
  24.  
  25. static id subcontractors = nil;        /* Master list of converters */
  26.  
  27. + registerSubcontractor: aConverter
  28.   {    if (!subcontractors)
  29.         subcontractors = [[List allocFromZone:[self zone]] init];
  30.     [subcontractors addObjectIfAbsent: aConverter];
  31.     return self;
  32.   }
  33.  
  34.  
  35. /*---------------------------------------------------------------------------*/
  36. /* unregister a converter from the list of conversion subcontractors */
  37.  
  38. + unregisterSubcontractor: aConverter
  39.   {    [subcontractors removeObject:aConverter];
  40.     return self;
  41.   }
  42.  
  43. /*---------------------------------------------------------------------------*/
  44. /* get the name of the next one in the list */
  45.  
  46. + getSubcontractor:(unsigned int) n {return [subcontractors objectAt:n];}
  47.  
  48.  
  49. /*===========================================================================*/
  50. /* General Class methods */
  51. /*===========================================================================*/
  52. /* Initialize the class */
  53.  
  54. + initialize
  55.   {[MiscCoordConverter setVersion:MISC_COORD_CONVERTER_VERSION_ID]; return self;}
  56.  
  57.  
  58. /*===========================================================================*/
  59. /* Initialization methods */
  60. /*===========================================================================*/
  61. /* We cache everything that we will need repeatedly, ie the class id's
  62.    of all the MiscCoord classes we know how to service.
  63.  
  64.    Every instance of a converter is registered so it can be subcontracted
  65.    to.
  66.  
  67. */
  68.  
  69. - init
  70.   {    [MiscCoordConverter registerSubcontractor: self];
  71.     return self;
  72.   }
  73.  
  74.  
  75. /*---------------------------------------------------------------------------*/
  76. /* Free self and subcontractor list, but NOT the subcontractors. 
  77.  
  78.     There is a potential problem: what if someone holds
  79.     a pointer to us? Some going out of business notification
  80.     would be necessary in that case.
  81.  
  82.     Most subclasses lock out free so this is not an immediate problem
  83. */
  84.  
  85. - free
  86.   {    [MiscCoordConverter unregisterSubcontractor:self];
  87.     [services free];
  88.     return [self free];
  89.   }
  90.  
  91.  
  92. /*===========================================================================*/
  93. /* Service support methods */
  94. /*===========================================================================*/
  95. /* For subclass use: add a service to our list of conversion services. */
  96.  
  97. - addService: (SEL) aSelector convertsFrom: (Class) one to: (Class) two 
  98.   {    struct __MiscService    theService;
  99.  
  100.     if (!services)
  101.         services = [[Storage allocFromZone:[self zone]]
  102.                   initCount: 0
  103.                 elementSize: MISC_SERVICE_SIZE
  104.                 description: MISC_SERVICE_DESCRIPTION];
  105.  
  106.     theService.iClass = one;
  107.     theService.oClass = two;
  108.     theService.xlator = aSelector;
  109.     [services addElement: (void*) &theService];
  110.     return self;
  111.   }
  112.  
  113.  
  114. /*---------------------------------------------------------------------------*/
  115. /* Internal method to search for a service in our list of conversion services.
  116.    We return the selector that can carry out the desired conversion,
  117.    or else a null selector if we cannot. It is assumed that a null selector
  118.    will always be undefined.
  119.  
  120. */
  121.  
  122. - (SEL) findServiceFrom: (Class) one to: (Class) two
  123.   {    struct    __MiscService    *theService;
  124.  
  125.     unsigned int    i, cnt = [services count];
  126.  
  127.     for (i=0; i<cnt; i++)
  128.      {    theService = (struct __MiscService *) [services elementAt:i];
  129.         if ((theService->iClass == one) &&
  130.             (theService->oClass == two)) return theService->xlator;
  131.      }
  132.     return    (SEL) 0;
  133.   }
  134.  
  135. /*===========================================================================*/
  136. /* Basic conversion methods (Internal use only) */
  137. /*===========================================================================*/
  138. /* Collect info we need to carry out the requested job
  139.  
  140.   NOTE: Any method that is sent to srcCoord or dstCoord must be in 
  141.     the MiscCoordConverterClient protocol!
  142. */
  143.  
  144. - prepareForJob: inCoord : outCoord
  145.   {
  146.     srcConstants  = [inCoord constants];
  147.     dstConstants  = [outCoord constants];
  148.     sameConstants = [srcConstants isEqual: dstConstants];
  149.  
  150.     dimensions    = [[inCoord class] dimensions];
  151.     npoints       = [inCoord  curBlockSize];
  152.  
  153.     src           = [inCoord  curPtr];
  154.     dst           = [outCoord curPtr];
  155.  
  156.     return    self;
  157.   }
  158.  
  159.  
  160. /*---------------------------------------------------------------------------*/
  161. /* a quick means of copying if data formats are identical. This method
  162.    is known outside by name, but should never be actually used outside
  163.    of applyTransform.
  164.  
  165.    It will fail if the constants associated with the two MiscCoords are not
  166.    functionally the same.
  167.  
  168. */
  169.  
  170. - (BOOL) copyCoords
  171.   {    int        len;
  172.  
  173.     if (!sameConstants) return NO;
  174.     len = dimensions * npoints * sizeof(double);
  175.     bcopy((char*)src, (char*)dst, len);
  176.  
  177.     return YES;
  178.   }
  179.  
  180.  
  181. /*---------------------------------------------------------------------------*/
  182. /* Apply the specified method to a block of coordinates. Job is set up
  183.    by prepareForJob: before this method is called.
  184. */
  185.  
  186. - (BOOL) applyTransform:(SEL)aSelector
  187.   {    unsigned int    i;
  188.  
  189.     /* copy has it's own loop */
  190.     if (aSelector == @selector(copyCoords))
  191.         [self perform: aSelector];
  192.     else 
  193.        for (i=0;
  194.             i<npoints;
  195.             i++,dst+=dimensions,src+=dimensions)
  196.             [self perform: aSelector];
  197.  
  198.     return YES;
  199.   }
  200.  
  201.  
  202. /*---------------------------------------------------------------------------*/
  203. /* Conversion setup method. This method sees if we or anyone we know of
  204.    can handle the requested job. If so, we return YES with local instance
  205.    vars theTransform and subContractor ready to go.
  206.  
  207.    NOTE: If you want to handle conversion between coords of different
  208.          dimensionality, look here first.
  209.  
  210.    Both MiscCoords must:
  211.     1) Conform to the MiscCoordConverterClient protocol.
  212.     2) Have the same dimensionality.
  213.     3) Have the same transfer blocksize pre-set to the same size.
  214.     4) Some Converter object must be willing to accept the job
  215.        of converting or copying between the two types.
  216.  
  217. */
  218.  
  219. - (BOOL) reviewSpecification: inCoord to: outCoord 
  220.   {    unsigned int    i;
  221.     Class        srcClass, dstClass;
  222.     BOOL        srcOk,dstOk;
  223.  
  224.     srcClass      = [inCoord  class];
  225.     dstClass      = [outCoord class];
  226.     srcOk          = [srcClass conformsTo:@protocol(MiscCoordConverterClient)];
  227.     dstOk          = [dstClass conformsTo:@protocol(MiscCoordConverterClient)];
  228.     if (!(srcOk && dstOk)) return NO;
  229.  
  230.     if ([srcClass dimensions]  != [dstClass dimensions])   return NO;
  231.     if ([inCoord curBlockSize] != [outCoord curBlockSize]) return NO;
  232.  
  233.     /* We should be able to handle it ourselves most of the time, or
  234.        else the customer has the wrong delegate! */
  235.  
  236.     if (theTransform = [self findServiceFrom: srcClass to: dstClass])
  237.         aSubcontractor = self;
  238.     else
  239.     /* If we can't do it ourselves, try subcontracting to one of the
  240.        other registered convertors
  241.     */
  242.     for (i=0; aSubcontractor = [MiscCoordConverter getSubcontractor:i]; i++)
  243.      {if (aSubcontractor == self) continue;
  244.       if (theTransform =
  245.           [aSubcontractor findServiceFrom: srcClass to: dstClass])
  246.           break;
  247.      }
  248.  
  249.     return ((theTransform) ? YES : NO);
  250.   }
  251.             
  252.  
  253. /*===========================================================================*/
  254. /* Misc Coord Converter Server protocol */
  255. /*===========================================================================*/
  256. /* Convert the specified block of coordinates from the source type to the
  257.    destination type if we are able, or if we can subcontract it to someone
  258.    else who is able to do it. If there is any reason at all that we
  259.    cannot, then return NO.
  260.  
  261.    DESIGN NOTE: Although local methods are executing, there may be one OR two
  262.    different objects with private storage involved. Care must be taken to
  263.    make sure that setup takes place in the correct object, ie usually the
  264.    subcontractor object. The subcontractor will often be self, in which case
  265.    setting ivars in this method would work: but if not, the subcontractor
  266.    would probably crash because things would not be set up in ITS' ivars.
  267.    THINK before making changes to where set up occurs!
  268.  
  269. */
  270.  
  271. - (BOOL) convert: inCoord to: outCoord 
  272.   {
  273.     if (![self reviewSpecification: inCoord to: outCoord]) return NO;
  274.     [aSubcontractor prepareForJob: inCoord : outCoord];
  275.     return [aSubcontractor applyTransform:theTransform];
  276.    }
  277.  
  278.  
  279. /*===========================================================================*/
  280. /* For Subclass use: We have a fast means of copying, but there is no need to
  281.    make it really public. To discourage possibly disastrous attempts to use it
  282.    directly, we supply a means of getting it's selector for use in an 
  283.    addService method by a subclass.
  284. */
  285.  
  286. - (SEL) fastCopySelector {return (@selector(copyCoords));}
  287.  
  288.  
  289. /*===========================================================================*/
  290. /* Archive methods */
  291. /*===========================================================================*/
  292. /* This class should not be used on its own. Presumably a subclass will 
  293.    re-generate it's services list when it awakes, or if it is a single
  294.    instance class, it will just delete this object when it answers with
  295.    a finishUnarchiving message.
  296. */
  297.  
  298. - awake
  299. {    [super awake];
  300.  
  301.     services = nil;
  302.     [MiscCoordConverter registerSubcontractor: self];
  303.     return self;
  304. }
  305.  
  306. @end
  307.